﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UtilZ.Dotnet.DBIBase;

namespace UtilZ.Dotnet.DBOracle
{
    internal partial class OracleDBAccess : DBAccessAbs
    {
        /// <summary>
        /// sql语句最大长度
        /// Oracle文档说是64K
        /// </summary>
        private const long SQL_MAX_LENGTH = 65536;
        public OracleDBAccess(IDBInteraction dbInteraction, DatabaseConfig config, string databaseTypeName)
            : base(dbInteraction, config, databaseTypeName, SQL_MAX_LENGTH)
        {

        }

        /// <summary>
        /// 最优化表,回收不使用的空间,并整理数据文件的碎片
        /// </summary>
        /// <param name="tableNames">表名列表,如果为null或空,则全部执行</param>
        protected override void PrimitiveOptimizeTable(List<string> tableNames)
        {
            /********************************************************************************
             * 在oracle中由于表结构设计不合理或者需要清楚老数据的时候，经常需要对大表数据进行清理。
             * 
             * 一般有一下几种方法：
             * 1.删除大部分数据，留下小部分数据。我们可以把需要保留的数据转移到别的表，然后再把大表drop掉，然后改名就行了；
             *      a) create table tablename_min as select* from tablename_max a where 需要保留的数据.
             *      b) drop table tablename_max;
             *      c) rename tablename_min as tablename_max;
             *
             *        这样就能清除这个大表的hwm，而且释放掉其他空间。
             * 2.当删除的数据只是一小部分数据的话，第一种方法就不适用了。比如 3亿条数据，你删除一亿条数据的话，用1就不合适。
             * 这时我们就应该考虑使用shrink table的方式。
             *     a) 我们可以先用delete from tablename_max;
             *     b) 由于我们进行了数据的delete 所以造成了 tablename_max 这张表的数据稀疏, 数据块并没有减少，hwm也没有减少，这样就会影响全表扫描需要访问更多的数据块。这时我们可以通过shrink来重组数据使数据分布 更紧密，同时降低HWM释放空闲数据块。
             *     c)由于需要移动行数据，数据的rowid会发生变化，所以需要设置表的row movement属性：
             *        alter table tablename_max enable row movement; --开启行迁移功能。
             *        alter table tablename_max shrink space compact; --(可以在压缩期间进行DML操作和查询) ,收缩表，不会降低hwm
             *        alter table tablename_max shrink space; --(调整HWM时将阻塞DML操作),收缩表，并且降低hwm
             *        alter table tablename_max shrink space cascade; --收缩表并降低hwm，并且回收相应的索引。
             *        由于我们删除了大量的数据 ，相应的索引也进行了删除，这时需要对索引进行收缩。
             *        alter index idxname shrink space;
             *        注意：shrink table只会针对assm（自动段空间管理）的表有用，否则会报： ORA - 10635: Invalid segment or tablespace type。
             *        alter table tablename_max enable row movement语句会造成引用表tablename_max的对象(如存储过程、包、视图等)变为无效。执行完成后，最好执行一下utlrp.sql来编译无效的对象。
             *        
             * 由于是注:通过DML操作进行的，会产生大量redo，注意archivelog目录的空间大小问题；同时undo表空间也会暴增。
             ********************************************************************************/

            using (var con = base.CreateConnection(DBVisitType.W))
            {
                if (tableNames == null || tableNames.Count == 0)
                {
                    List<DBTableInfo> list = this.PrimitiveGetTableInfoList(con.DbConnection, false);
                    tableNames = list.Select(t => { return t.Name; }).ToList();
                }

                foreach (var tableName in tableNames)
                {
                    string sql = $@"ALTER TABLE {tableName} ENGINE=INNODB";//重新创建表,并拷贝数据
                    base.PrimitiveExecuteNonQuery(sql, DBVisitType.W, null);
                }
            }
        }

        /// <summary>
        /// 创建数据库对象
        /// </summary>
        /// <returns></returns>
        protected override IDatabase CreateDatabase()
        {
            return new OracleDatabase(this);
        }
    }
}
